import { WeaTools } from "ecCom";
import { toJS } from 'mobx';
import EditorUtil from "../../util/ckextraEditorUtil";
import keyUtil from '../../util/keyUtil';
import RangeUtil from '../../util/ckextraRangeUtil';
import RevisionItem from './RevisionItem';
import TagUtil from "../../util/ckextraTagUtil";
import CkextraWindowUtil from '../../util/ckextraWindowUtil';
import ListAdUtil from '../../util/ckextraListAdUtil';
import Postil from '../../components/ckextra/Postil';

export default class RevisionCk {
  revision = null;
  postil = null;
  constructor(revisionStore) {
    this.revision = revisionStore;
  }

  // hasAddedListener = false;
  revising = false;
  shouldRevise = false;
  isLock = false;

  deletingNodeInfoList = [];
  deletedPTag = null;

  isCut = false;
  isUndoRedo = false;
  mergeAll = false;
  deleteParent = null; // 记录删除时候的父节点
  containedPostilIds = []; // 记录删除的时候，当前包含的postil的id

  isLockDom = false;
  
  inputValue = ''; // 记录非中文连续输入的内容

  /**
   * 删除传入range的内容。range中的内容有可能已经被删。
   * 针对range内容，将原文改为删除标记，将新写的内容（u标签）直接删除，已删的内容（s标签)不变。
   * @param range
   */
  deleteByRange = (range) => {
    // let children = RangeUtil.getRangeChildren(range);
    const children = this.getRangeChildren(range);
    range.deleteContents();
    return this.delAndInsert(children);
  }

  delAndInsert = (nodeInfoList) => {
    const curRange = EditorUtil.getRanges()[0];
    const delNodes = this.deleteByNodeInfoList(nodeInfoList);
    if (!delNodes || delNodes.length === 0) return curRange;
    if (curRange) {
      curRange.optimizeBookmark();
      curRange.trim(false, true);
      const {startContainer, startOffset} = curRange;
      let p = startContainer;
      // 判断是否文件末尾
      while(EditorUtil.isNode(p) && !EditorUtil.isParagraph(p) && (p = p.getParent()));
      if (!EditorUtil.isNode(p)) {
        if (startContainer.getChild(startOffset).getName() === 'br') {
          startContainer.getChild(startOffset).remove();
        }
        p = EditorUtil.getEditor().document.createElement('p');
        // fix： 删除的时候文号的class没有了
        if (this.deleteParent) {
          const cls = this.deleteParent.$.className;
          if (cls && cls !== '')
          p.setAttribute('class', cls);
        }
        EditorUtil.getEditor().insertElement(p);
        curRange.setStart(p, 0);
        curRange.setEnd(p, 0);
        curRange.select();
      }
    }

    const ranges = EditorUtil.getEditor().getSelection().getRanges();
    const range = ranges[0];
    let { startContainer } = range;
    if (startContainer.$.parentNode && startContainer.$.parentNode.getAttribute('listadvancetype')) {
      let curIndex;
      for (let i = 0; i < delNodes.length; i++) {
        let node = delNodes[i];
        if ((node.getName && node.getName() === 'p') || i > 0) {
          range.setStartBefore(startContainer);
          startContainer = range.startContainer;
          curIndex = i;
          break;
        } else {
          if (!(node.getName && node.getName() === 'br')) {
            range.insertNode(node);
          }
        }
      }
      if (curIndex) {
        const resDelNodes = delNodes.slice(curIndex).reverse();
        resDelNodes.forEach(node => {
          if (!(node.getName && node.getName() === 'br')) {
            node.insertAfter(startContainer)
          }
        });
      }

    } else {
      delNodes.forEach((node, index) => {
        if (!(node.getName && node.getName() === 'br')) {
          EditorUtil.getEditor().insertElement(node);
        }
      });
    }

    // delNodes.forEach((node, index) => {
    //   EditorUtil.getEditor().insertElement(node);
    // });
    
    let endContainer = delNodes[delNodes.length - 1], endOffset = EditorUtil.getContentLength(endContainer);
    curRange.setEnd(endContainer, endOffset);
    return curRange;
  }

  // 删除的时候将所选的节点合并为一个 s节点 --> 这里应该只有有个s节点，原本的写法是一个list，这里就把这个节点放在list中
  // createNewDelNode = (nodeInfoList) => {
  //   const delNodeList = [];
  //   const newElement = new RevisionItem({
  //     parent: this.revision,
  //     revisionCk: this,
  //     type: 'D',
  //     containedPostilIds: this.containedPostilIds.join(','),
  //   });
  //   const newNode = newElement.createDom();
  //   const delChildNodes = this.getChildDelNodes(nodeInfoList);
  //   delChildNodes.forEach(({node, type}) => {
  //     if (type === 'text') {
  //       newNode.appendText(node);
  //     } else {
  //       newNode.append(node);
  //     }
  //   })
  //   delNodeList.push(newNode);
  //   return delNodeList;
  // }

  // 获得当前s标签内所有的子节点以及子节点的子节点
  getChildDelNodes = (nodeInfoList) => {
    const delChildNodes = [];
    nodeInfoList.forEach((nodeInfo) => {
      const {node, type} = nodeInfo;
      if (type === 'I') {
        return;
      }
      // 文本删除的时候合并
      if (node instanceof CKEDITOR.dom.text) {
        const text = typeof(node) === 'string' ? node: node.getText();
        if (text !== '') { // 空内容不处理
          delChildNodes.push({
            node: text,
            type: 'text',
          });
        }
      } else if (node instanceof CKEDITOR.dom.element) {// element删除的时候遍历合并子节点
        if (node.getChildCount() > 0) {
          const newChildNode = node.clone();
          const childNodes = this.getChildDelNodes(RangeUtil.convertToNodeInfoList(node.getChildren().toArray()));
          childNodes.forEach(({node, type}) => {
            if (type === 'text') {
              newChildNode.appendText(node);
            } else {
              newChildNode.append(node);
            }
          });
          delChildNodes.push({
            node: newChildNode,
            type: 'node',
          });
        } else {
          // 有值或者是POSTIL节点，直接push进去 （空内容不处理）
          const nodeName = node.getName();
          const text = node.getText();
          if (text !== '' || nodeName === 'postil') {
            delChildNodes.push({
              node: node,
              type: 'node',
            })
          }
        }
      }
    });
    return delChildNodes;
  }

  deleteByNodeInfoList = (nodeInfoList) => {
    let delNodes = [];
    nodeInfoList.forEach((nodeInfo) => {
      const {node, type} = nodeInfo;
      if (type === 'I') return;
      if (node instanceof CKEDITOR.dom.text) {
        const text = typeof(node) === 'string' ? node: node.getText();
        if (text !== '') { // 空内容不处理
          const delItem = new RevisionItem({
            parent: this.revision,
            revisionCk: this,
            type: 'D',
            text: text,
            containedPostilIds: this.containedPostilIds.join(','),
          });
          const delNode = delItem.createDom();
          delNodes.push(delNode);
        }
      } else if (node instanceof CKEDITOR.dom.element) {
        if (node.getChildCount() > 0) {
          const delChildNodes = this.deleteByNodeInfoList(RangeUtil.convertToNodeInfoList(node.getChildren().toArray()));
          while(node.$.firstChild){
            node.$.removeChild(node.$.firstChild);
          }
          delChildNodes.forEach((delNode) => node.append(delNode));
        }
        delNodes.push(node);
      } else {
        console.warn("未知情况", node);
      }
    });
    return delNodes;
  }

  lockUndo = () => {
    if (!this.isLock) {
      this.isLock = true;
      EditorUtil.getEditor().undoManager.lock(true);
    }
  }

  unLockUndo = (needSave = true) => {
    if (this.isLock) {
      EditorUtil.getEditor().undoManager.unlock();
      setTimeout(() => {
        EditorUtil.getEditor().undoManager.unlock();
        needSave && EditorUtil.getEditor().undoManager.save();
        this.isLock = false;
      }, 0);
    }
  }

  insertDeletingNode = (isCursorStart) => {
    // 选中后删除的逻辑处理
    if (Array.isArray(this.deletingNodeInfoList) && this.deletingNodeInfoList.length > 0) {
      // console.log('deletingNodeInfoList', toJS(this.deletingNodeInfoList))
      const range = this.delAndInsert(this.deletingNodeInfoList);
      if (isCursorStart) {
        range.setEnd(range.startContainer, range.startOffset);
      } else {
        range.setStart(range.endContainer, range.endOffset);
      }
      range.select();
      this.deletingNodeInfoList = [];
    }
  }

  /** 格式化text节点、删除ck加入的空格、合并删除节点、保证这些完成后光标位置不变 **/
  formatAndMergeCurrent = (mergeAll) => {
    let rangeIndex = RangeUtil.getCurrentIndex();
    // if (mergeAll) {
    //   EditorUtil.mergeAll(this.revision);
    // } else {
    //   EditorUtil.mergeCurrentNode(this.revision);
    // }
    // fix: 痕迹遗漏、拆分问题
    EditorUtil.mergeAll(this.revision);

    EditorUtil.normalizeCurrent();
    let pos = RangeUtil.getPositionByIndex(rangeIndex);
    if (!pos) return;
    let range = EditorUtil.getEditor().createRange();
    range.setStart(pos.container, pos.offset);
    range.setEnd(pos.container, pos.offset);
    range.select();
  }

  /**
   * 序号 div dom节点 添加DOMNodeRemovedFromDocument监听事件
   */
  handlerDOMNodeRemovedFromDocument = () => {
    const editor = EditorUtil.getEditor();
    let doms = editor.document.find('div').toArray();
    const ListNode = CKEDITOR.plugins.listAdvance.ListNode;
    if (!this.isLockDom) {
      this.isLockDom = true;
      doms.reverse().forEach(dom => {
        ListNode.handlerDOMNodeRemovedFromDocument({num: dom.getAttribute('data-num'), key: dom.getAttribute('data-key'), type: dom.getAttribute('listadvancetype')}, dom);
      });
    }
    setTimeout(() => this.isLockDom = false, 0);
  }

  /**
   * 序号 第一行内容为空时，强制删除第一行序号并排序
   */
  removeFirstLine = () => {
    const editor = EditorUtil.getEditor();
    let doms = editor.document.find('div').toArray();
    const ListNode = CKEDITOR.plugins.listAdvance.ListNode;
    if (!this.revising && doms && doms.length > 0) {
      ListNode.removeFirstLine(doms);
    } else if (this.revising && doms && doms.length === 1) {
      if (doms[0].getHtml().match(/^<p></)) {
        const parentNode = doms[0].getParent();
        const childNodes = doms[0].getChildren().toArray();
        if (childNodes.length === 1) {
          childNodes.forEach(node => {
            parentNode.append(node);
          });
          if (doms[0].getText().length === 0) doms[0].remove();
        }
      }
    }
  }

  /**
   * 添加监听事件
   */
  addCKListener = () => {
    // if (this.hasAddedListener) return;
    let editor = EditorUtil.getEditor(), body = editor.document.getBody();
    editor.on('key', this.onKeyDown);
    editor.on('beforePaste', this.beforePaste);
    editor.on('paste', this.onPaste);
    editor.on('afterPaste', this.afterPaste);
    editor.on("afterCommandExec", (evt) => {
      const {name} = evt.data;
      if (name === 'undo' || name === 'redo') {
        this.revision.refresh();
        this.revision.clearAvtiveRevisionParams();
        // 撤销操作之后，序号（div）节点绑定的事件丢失处理
        this.lockUndo();
        this.handlerDOMNodeRemovedFromDocument();
        this.unLockUndo();
      }
    });
    //可编辑区域外点击，触发body的click事件
    document.getElementsByClassName('cke_wysiwyg_frame')[0].contentWindow.addEventListener('click', (e) => {
      let myEvent = new Event('click');
      document.getElementsByClassName('cke_wysiwyg_frame')[0].contentDocument.body.dispatchEvent(myEvent);
    });
    //防止切换TABLE时，输入无痕迹的情况
    body.on('focus', this.onClick);
    //防止点击到删除区域后，无法定位到修订内容的情况。
    body.on('click', this.onClick);
    //body.on('click', this.revision.refreshChooseStatus);
    body.on('keyup', this.onKeyUp);
    body.on('keyup', this.revision.refreshChooseStatus);
    body.on('compositionend', this.onCompositionEnd);
    body.on('compositionend', this.revision.refreshChooseStatus);
    // this.hasAddedListener = true;
  }

  /**
   * keydown事件
   * @param event
   */
  onKeyDown = (event) => {
    if (!this.revising) return;
    const selectedPostilIds = Postil.getCurrentStore().getChooseItemIds(); //当前范围内的postilIds
    // console.log('selectedPostilIds', selectedPostilIds)
    // 处理删除逻辑，以及在有选择内容的情况下按下键时，删除的前置准备
    let selectedText = EditorUtil.getEditor().getSelection().getSelectedText();
    let ranges = EditorUtil.getEditor().getSelection().getRanges();
    if (ranges.length < 1) return;
    let range = ranges[0];
    const { startContainer, startOffset, endContainer, endOffset } = range;

    let e = event.data.domEvent.$;
    if (keyUtil.isUndoRedo(e)) {
      this.isUndoRedo = true;
      return;
    }

    // enter fix: enter的时候 带序号复制 enter生成删除的标签
    if(keyUtil.isEnter(e)) {
      return;
    }

    this.lockUndo();
    //如果有选中内容且是输入内容，则记录删除信息
    // todo : mac系统 command + c 复制 也会记录成删除信息
    if((keyUtil.isCut(e) || keyUtil.isNotCmdKey(e)) && selectedText.length > 0){
      const rangeList = this.getRangeChildren(range, !keyUtil.isInput(e));
      this.deletingNodeInfoList = (this.deletingNodeInfoList || []).concat(rangeList);
      this.isCut = keyUtil.isCut(e);

      // 选中情况下，直接替换containedPostilIds
      this.containedPostilIds = selectedPostilIds;
      return ;
    }

    //只处理删除内容的逻辑
    if(!keyUtil.isBackspace(e) && !keyUtil.isDelete(e)) {
      this.containedPostilIds = [];
      return;
    } else { // 是连续删除
      const newArr = [
        ...this.containedPostilIds,
        ...selectedPostilIds,
      ];
      this.containedPostilIds = newArr.length > 0 ? Array.from(new Set(newArr)) : [];
    }

    // 根据是backspace还是delete,获得前一位/后一位的range位置
    range = keyUtil.isBackspace(e) ? RangeUtil.getPreviousOneRange(range) : RangeUtil.getNextOneRange(range);
    if (!range) return;

    range.select();

    // 记录当前删除的父节点 -- 最后一行只有一个字符删除的时候需要用到父元素的className
    const parent = RangeUtil.getParentNode(range).root;
    if (parent) {
      this.deleteParent = parent;
    }

    const rangeList = this.getRangeChildren(range);
    this.deletingNodeInfoList = (this.deletingNodeInfoList || []).concat(rangeList);
    this.mergeAll = true;
  }

  /**
   * keyup事件
   * @param event
   */
  onKeyUp = (event) => {
    let e = event.data.$;
    //输入法输入状态判断
    if (e.isComposing) return;
    // undoRedo与纯粹的shift/alt/ctrl/esc不做解锁、合并等操作，直接返回。
    if (this.isUndoRedo) {
      this.isUndoRedo = false;
      return;
    }
    if (keyUtil.isCmdKey(e)) {
      return;
    }
    // enter
    if(keyUtil.isEnter(e)) {
      return;
    }
    if (this.revising) {
      if (EditorUtil.getSelectedText()) {
        //如果此时依旧有选中内容，则只做解锁处理
        this.unLockUndo();
        // this.revision.clearChooseItemId();
        return;
      }

      let mergeAll = this.deletingNodeInfoList.length > 0;
      // 增加isCut记录，避免遇到ctrl与x一起松导致x的keyup中ctrl为false;
      if (this.deletingNodeInfoList.length > 0 && keyUtil.isInput(e) && !this.isCut) {
        // fix: 快速连续输入数字英文 （或者有按住不放的时候）
        this.inputValue = this.inputValue += e.key;
        // inputValue = EditorUtil.getAndDelInput(this.inputValue);
      }
      this.isCut = false;
      // 选中后删除或输入的逻辑处理
      let isCursorStart = keyUtil.isBackspace(e);


      const func = (hasInputValue = false) => { // delAndInsert -- 选中并输入内容情况
        if (hasInputValue) {
          this.inputValue = EditorUtil.getAndDelInput(this.inputValue);
        }
        this.insertDeletingNode(isCursorStart);
        // 如果inputValue有值，为了让它能有id并在左侧显示，需要提前插入
        if (hasInputValue) {
          TagUtil.insertTempUtag(this.inputValue, this.revising);
        }
        this.inputValue = '';

        this.formatAndMergeCurrent(mergeAll || this.mergeAll);
        this.mergeAll = false;

        // 刷新左侧列表
        this.revision.refresh();
        // 插入u标签。
        TagUtil.insertTempUtag('',this.revising);
        this.unLockUndo();

        //删除多余BR标签
        if(keyUtil.isDelete(e) || keyUtil.isBackspace(e))
        TagUtil.clearBrTag();
      }

      if (this.inputValue !== '') {// 有输入内容的时候，需要输入结束后再执行删除和插入操作
        setTimeout(() => {
          func(true)
        }, 1000);
      } else {
        func()
      }
    } else {
      // 非修订模式对在修订下插入内容的处理
      this.lockUndo();
      if (EditorUtil.getSelectedText()) return;
      if (keyUtil.isDirectionKey(e) && RangeUtil.isInInsertNode()) {
        EditorUtil.lock();
        let element = new RevisionItem({type: 'T'}).createDom();
        TagUtil.insertElementWithOutSaveTodo(element);
        let range = EditorUtil.getRanges()[0];
        range.moveToPosition( element, CKEDITOR.POSITION_BEFORE_END);
        range.select();
        EditorUtil.unlock();
      }
      if (RangeUtil.isInTempTextNode()) {
        this.formatAndMergeCurrent(false);
      }
      // 处理在行末回车的情况下，继续保留u标签的情况
      if (RangeUtil.isInInsertNode()) {
        let container = RangeUtil.getStartContainer();
        if (RevisionItem.checkRevisionType(container) && !EditorUtil.clearEmptyChar(container.getText())) {
          container.remove();
        }
      }
    }
    //定位选中的样式
    const frame = document && document.getElementsByClassName('cke_wysiwyg_frame');
    if (frame && frame[0]) {
      resetSelectedClass && resetSelectedClass(frame[0].contentWindow.getSelection());
    }
    // 第一行序号中内容为空的情况下，强制删除这一行序号
    if (keyUtil.isDelete(e) || keyUtil.isBackspace(e)) this.removeFirstLine();
    if (!this.revising) this.unLockUndo();
  }

  onCompositionEnd = (event) => {
    if (this.revising) {
      let inputValue = '', mergeAll = this.deletingNodeInfoList.length > 0;
      if (this.deletingNodeInfoList.length > 0) {
        let e = event.data.$;
        inputValue = e.data;
        if (inputValue) {
          inputValue = EditorUtil.getAndDelInput(inputValue, true);
        }
      }
      this.insertDeletingNode(false);
      TagUtil.insertTempUtag(inputValue,this.revising);
      this.formatAndMergeCurrent(mergeAll || this.mergeAll);
      this.mergeAll = false;
      // 刷新左侧列表
      this.revision.refresh();
      // 插入u标签。
      TagUtil.insertTempUtag('',this.revising);
      this.unLockUndo();
      // this.revision.clearChooseItemId();
    } else {
      // 非修订模式，在修订内容中插入文本的处理 - start
      const ranges = EditorUtil.getEditor().getSelection().getRanges();
      const range = ranges[0];
      if (range) {
        const { startContainer } = range;
        const parent = startContainer.getParent();
        if (parent.getName() === 'u' || parent.getParent().getName() === 'u') {
          EditorUtil.lock();
          const element = new RevisionItem({type: 'T'}).createDom();
          TagUtil.insertElementWithOutSaveTodo(element);
          range.moveToPosition( element, CKEDITOR.POSITION_BEFORE_END);
          range.select();
          EditorUtil.unlock();
        }
        if (RangeUtil.isInTempTextNode()) {
          this.formatAndMergeCurrent(false);
        }
        // 非修订模式，在修订内容中插入文本的处理 - end
      }
      EditorUtil.getEditor().fire( 'saveSnapshot' );
    }
    EditorUtil.getEditor().undoManager.editingHandler.keyEventsStack.resetInputs();
  }

  beforePaste = (event) => {
    if (!this.revising) return;
    this.lockUndo();
    if (EditorUtil.getSelectedText().length > 0) {
      let range = this.deleteByRange(EditorUtil.getRanges()[0]);
      range.setStart(range.endContainer, range.endOffset);
      range.select();
      TagUtil.insertTempUtag('',this.revising);
    }
  }

  onPaste = (event) => {
    const dataValue = event.data.dataValue;
    // 转化成dom节点之后 过滤 过滤完成后 转换的dom节点的innerHtml替换dataValue
    if (!this.revising) this.lockUndo();
    const dom = CKEditorParams.editorObject.document.createElement('div');
    const newDom = CKEditorParams.editorObject.document.createElement('div');
    dom.appendHtml(dataValue);
    const childList = dom.getChildren().toArray();
    const filterChildList = this.filterPasteValue(childList);
    filterChildList.forEach(node => newDom.append(node));
    const value = newDom.getHtml();
    event.data.dataValue = value;
    event.data.type = 'text';
  }

  // 过滤 粘贴的文本内容 
    // postil s 不要
    // u 非修订只要文本，修订情况操作者和时间（后期会自动生成新的）
    // 序号div || p 需要保留序号，但是中间的内容 也要 区分是否postil s u
  filterPasteValue = (childArr) => {
    const nodeList = [];
    childArr.forEach(child => {
      if (EditorUtil.isElement(child)) {
        if (child.getName() === 'postil' || child.getName() === 's' || child.getName() === 'temptext') {
          return;
        } else if (child.getName() === 'p') { // p
          const pNode = child.clone();
          const pList = child.getChildren().toArray();
          const filterPList = this.filterPasteValue(pList);
          filterPList.forEach(node => pNode.append(node));
          nodeList.push(pNode);
        } else if (child.getAttribute('listadvancetype')) { // 序号情况 复制保留序号
          const ranges = EditorUtil.getRanges();
          const startContainer = ranges.length > 0 ? ranges[0].startContainer : null;
          const startAllParents = RangeUtil.getParentsFromRoot(startContainer);
          const divDoms = startAllParents.filter(dom => {
            if (!EditorUtil.isRoot(dom) && !EditorUtil.isText(dom) && EditorUtil.isNode(dom)) {
              return dom.getName() === 'div';
            }
            return false;
          });
          if ((startContainer && EditorUtil.isText(startContainer)) || divDoms.length > 0) {
            //光标位置在文本行，未另起一行的时候，只需要保留文本
            const node = CKEditorParams.editorObject.document.createText(child.getText());
            nodeList.push(node);
          } else {
            const advanceNode = child.clone();
            const advanceList = child.getChildren().toArray();
            const filterAdvanceList = this.filterPasteValue(advanceList);
            filterAdvanceList.forEach(node => advanceNode.append(node));
            nodeList.push(advanceNode);
          }
        } else if (child.getName() === 'u') { // u 
          if (!this.revising) { // 非修订模式： 只需要保留文本
            const node = CKEditorParams.editorObject.document.createText(child.getText());
            nodeList.push(node);
          } else { // 修订模式：不需要复制 修订人 和 修订时间
            child.setAttribute('xiudingren', '');
            child.setAttribute('xiudingshijian', '');
            nodeList.push(child);
          }
        } else {
          nodeList.push(child);
        }
      } else {
        nodeList.push(child);
      }
    });
    return nodeList;
  }

  afterPaste = (event) => {
    if (this.revising) {
      this.formatAndMergeCurrent(true);
      this.revision.refresh();// 刷新左侧列表
      TagUtil.insertTempUtag('',this.revising);// 插入u标签。
      // 序号（div）节点绑定的事件丢失处理
      this.handlerDOMNodeRemovedFromDocument();
    } else {
      // 判断粘贴之后是否有重复的修订id
      this.lockUndo();
      let nodes = EditorUtil.getEditor().document.find('s,u').toArray(), idMap = {};
      let hasRepeatId = nodes.some((node) => {
        let id = node.getId();
        if (idMap[id]) {
          return true;
        }
        idMap[id] = true;
        return false;
      });
      // 有重复id则重新生成所有修订节点
      if (hasRepeatId) {
        let rangeIndex = RangeUtil.getCurrentIndex();
        EditorUtil.mergeAll(this.revision);
        this.revision.refresh();
        let pos = RangeUtil.getPositionByIndex(rangeIndex);
        if (!pos) return;
        let range = EditorUtil.getEditor().createRange();
        range.setStart(pos.container, pos.offset);
        range.setEnd(pos.container, pos.offset);
        range.select();
      }
    }
    // 复制内容，更新序号,重新排序的过程无需记录痕迹
    this.lockUndo();
    const editor = EditorUtil.getEditor();
    const ListNode = CKEDITOR.plugins.listAdvance.ListNode;
    const doms = editor.document.find('div').toArray().filter(dom => dom.getAttribute('data-num') === '1');
    ListNode.refreshNumber(doms);
    this.unLockUndo();
  }

  onClick = (event) => {
    window.setTimeout(() => {
      //点击文字选中对应的样式

      // fix: 偶发的报错 Cannot read property 'className' of undefined
      // resetSelectedClass(document.getElementsByClassName('cke_wysiwyg_frame')[0].contentWindow.getSelection());
      const frame = document && document.getElementsByClassName('cke_wysiwyg_frame');
      if (frame && frame[0]) {
        resetSelectedClass && resetSelectedClass(frame[0].contentWindow.getSelection());
      }
      
      if (EditorUtil.getSelectedText()) return;
      if (this.revising) {
        this.revision.refreshChooseStatus(); // fix: 点击的时候revision active的id没有更新问题
        EditorUtil.lock();
        TagUtil.clearTempUTag();
        TagUtil.insertTempUtag('',this.revising);
        EditorUtil.unlock();
        // this.revision.clearChooseItemId();
      } else {
        //新增段落结尾U标签判断
        if (RangeUtil.isInInsertNode() || RangeUtil.isInEndInsertNode()) {
          EditorUtil.lock();
          let element = new RevisionItem({type: 'T'}).createDom();
          TagUtil.insertElementWithOutSaveTodo(element);
          let range = EditorUtil.getRanges()[0];
          range.moveToPosition( element, CKEDITOR.POSITION_BEFORE_END);
          range.select();
          EditorUtil.unlock();
        }
      }
    }, 0);
  }

  // 过滤 listAdvance 的div节点（删除的时候不需要保留，直接规过滤掉,取div内部的p标签）
  filterAdvanceNode = (list) => list.map(item => {
    if (EditorUtil.isElement(item) && item.getName() === 'div') {
      return item.getChildren().toArray()[0];
    }
    return item;
  })

  // 处理得到当前range范围内的children （fix: 删除得到的range不包含 postil问题）
  // needFindPostil: 直接删除需要过滤， 选中输入内容情况，除了刚好在前后psotil包裹范围内，其他情况需要过滤
  getRangeChildren = (range, needFindPostil = false) => RangeUtil.getRangeChildren(range, needFindPostil)

  toggleRevising = (show) => {
    this.shouldRevise = typeof(show) === 'undefined' ? !this.shouldRevise : !!show;
    // fix: 切换到非修订模式，在原有痕迹记录后面或者回车输入的内容，切换到修订模式时，依然是带痕迹的
    TagUtil.clearTempUTag();
  }

  showRevising = (show) => {
    this.revising = !!show;
    this.show(this.revising);
    this.addCKListener();
    const curData = EditorUtil.getEditor().getData();
    EditorUtil.getEditor().fire( 'saveSnapshot' );
  }

  choose = (id) => {
    // fix: 选中当前修订的时候也会记录一次: 先锁上，再解锁
    const editor = EditorUtil.getEditor();
    editor.focusManager.lock();

    const node = RevisionItem.findNodeById(id);
    if (node === null) return;
    let range = editor.createRange();
    range.setStartAt( node, CKEDITOR.POSITION_BEFORE_START );
    range.setEndAt( node, CKEDITOR.POSITION_AFTER_END );
    editor.focus();
    editor.getSelection().selectRanges( [ range ] );
    node.scrollIntoView(true);

    setTimeout(() => {
      editor.focusManager.unlock();
    }, 0);
  }

  receive = (id) => {
    this.lockUndo();
    let item = RevisionItem.findItemById(id);
    if (item) {
      // 判断item上方有没有ListNode;
      let node = ListAdUtil.getListNodeElementFromParent(item.node);
      item.receive();
      node && ListAdUtil.checkAndRemoveEmpty(node);
      // 修订模式下删除，接受的时候调用批注的doTrim方法，去掉当前修订的批注
      if (item.type === 'D') {
        Postil.getCurrentStore().doTrim(item.containedPostilIds.split(','));
        //fix: 非修订模式，含批注的内容选中输入新的内容，批注没有随之删除
        Postil.getCurrentStore().refreshChooseStatus(true);
      }
    }
    setTimeout(() => {
      this.unLockUndo();
    }, 0);
  }

  reject = (id) => {
    this.lockUndo();
    let item = RevisionItem.findItemById(id);
    if (item) {
      // 判断item上方有没有ListNode;
      let node = ListAdUtil.getListNodeElementFromParent(item.node);
      item.reject();
      node && ListAdUtil.checkAndRemoveEmpty(node);
    }
    setTimeout(() => {
      this.unLockUndo();
    }, 0);
  }

  getAllItems = () => {
    const editor = EditorUtil.getEditor();
    let list = [];
    let idMap = {};
    let nodes = editor.document.find('s,u').toArray();
    nodes.forEach((node) => {
      let id = node.getId();
      if (idMap[id]) return;
      idMap[id] = true;
      list.push(new RevisionItem({node, type: RevisionItem.getNodeRevisionType(node)}));
    });
    return list;
  }

  show = (bool) => {
    //编辑区域的修订显示隐藏
    let iframeBody = EditorUtil.getEditor().document.getBody().$;
    if (!iframeBody) return;
    let delList = iframeBody.getElementsByTagName("s");
    let insList = iframeBody.getElementsByTagName("u");

    // 找到所有的序号，并筛选出序号中都是删除节点的。
    let parentRedundantList = [...delList, ...insList]
      .map((node) => new CKEDITOR.dom.node(node))
      .map((node) => ListAdUtil.getListNodeElementFromParent(node))
      .filter((node) => !!node );
    let parentList = [];
    parentRedundantList.forEach((parent) => {
      if (parentList.some((item) => item.equals(parent))) {
        return;
      }
      let list = RevisionItem.convertDomToList(parent);
      list = list.filter(({node}) => node && EditorUtil.clearEmptyChar(node.getText()) );//不处理没有记录node节点与node节点没有值的。
      for (let i=0; i<list.length; i++) {
        let {item} = list[i];
        if (!item) return;//不存在说明是text节点，有非修订节点的序号不隐藏
        if (item.type === 'I') return;// 有新增修订的序号不隐藏
      }
      parentList.push(parent);
    } );


    const ListNode = CKEDITOR.plugins.listAdvance.ListNode;
    if(bool){
      for(let i =0; i < delList.length;i++){
        jQuery(delList[i]).removeClass('hiddenRevision_s');
      }
      for(let i =0; i < insList.length;i++){
        jQuery(insList[i]).removeClass('hiddenRevision_u');
      }
      ListNode.showListNodes(parentList);
    }else{
      for(let i =0; i < delList.length;i++){
        jQuery(delList[i]).addClass('hiddenRevision_s');
      }
      for(let i =0; i < insList.length;i++){
        jQuery(insList[i]).addClass('hiddenRevision_u');
      }
      ListNode.hideListNodes(parentList);
    }
    // 避免出现隐藏/显示修订后可以撤回上一次的状态的问题
    EditorUtil.getEditor().undoManager.reset();
  }

  findNext = () => {
    let ranges = EditorUtil.getRanges();
    if (ranges.length === 0) return null;
    let range = ranges[0];
    let revision = null, allItems = this.getAllItems().filter((item) => item.id >=0 && item.text ), container = RangeUtil.getEndContainer(range);
    allItems.forEach((item) => {
      if (revision) return;
      let containerSortNum = RangeUtil.sortNode(container, item.node);
      if (containerSortNum < 0) {
        revision = item;
      }
    });
    return revision;
  }
  findPrevious = () => {
    let ranges = EditorUtil.getRanges();
    if (ranges.length === 0) return null;
    let range = ranges[0];
    let revision = null, allItems = this.getAllItems().filter((item) => item.id >=0 && item.text ), container = RangeUtil.getStartContainer(range);
    allItems.reverse().forEach((item) => {
      if (revision || container.equals(item.node)) return;
      let containerSortNum = RangeUtil.sortNode(container, item.node);
      if (containerSortNum > 0) {
        revision = item;
      }
    });
    return revision;
  }

  chooseCurrentRevisionNode = () => {
    let ranges = EditorUtil.getRanges();
    if (ranges.length === 0) return null;
    let range = ranges[0], {startContainer, endContainer} = range;
    if (!startContainer.equals(endContainer)) return null;
    if(!EditorUtil.isText(startContainer) && startContainer.getName() === 'u' && !startContainer.$.id && startContainer.getParent().getName() === 's'){
      startContainer = startContainer.getParent();
    }

    if (EditorUtil.isText(startContainer)) {
      startContainer = startContainer.getParent();
    }
    if (EditorUtil.isParagraph(startContainer) || EditorUtil.isRoot(startContainer))
      return null;
    let item = RevisionItem.convertDomToItem(startContainer);
    try {
      if (item.type === 'I' && !item.text) {
        let container = startContainer;
        while(container && !EditorUtil.clearEmptyChar(container.getText())) {
          container = container.getNext();
        }
        item = RevisionItem.convertDomToItem(container);
        if (!item) {
          container = startContainer;
          while(container && !EditorUtil.clearEmptyChar(container.getText())) {
            container = container.getPrevious();
          }
          item = RevisionItem.convertDomToItem(container);
        }
      }
    } catch (e) {
      if(window.console)console.log();
    }
    return item;
  }
}